import datetime

from coin.exchange.base.kr_rest.derivative_util import (PERPETUAL_DATE)
from coin.exchange.deribit_v1.kr_rest.futures_constants import (contract_type_list,
                                                                quarter_contract_date)
import coin.exchange.okex_futures.kr_rest.exp_util as exp_util


def find_contract_type_from_expiry(current_datetime, expiry):
  if expiry == PERPETUAL_DATE:
    return 'perpetual'

  expiry = exp_util.expiry_accurate_datetime(expiry)
  if expiry == find_quarter_contract_expiring_date(current_datetime):
    return 'quarter'
  elif expiry == find_next_quarter_contract_expiring_date(current_datetime):
    return 'next_quarter'
  else:
    raise ValueError(current_datetime, expiry)


def find_expiry_from_contract_type(current_datetime, contract_type):
  if contract_type == 'perpetual':
    return PERPETUAL_DATE

  assert contract_type in contract_type_list
  if contract_type in ['current_quarter', 'quarter']:
    return find_quarter_contract_expiring_date(current_datetime)
  elif contract_type == 'next_quarter':
    return find_next_quarter_contract_expiring_date(current_datetime)
  else:
    raise ValueError(current_datetime, contract_type)


def to_expiry_contract_type(expiry_str, current_datetime):
  if expiry_str == 'perpetual':
    expiry = PERPETUAL_DATE
    contract_type = 'perpetual'
  elif expiry_str in contract_type_list:
    contract_type = expiry_str
    expiry = find_expiry_from_contract_type(current_datetime, contract_type)
  elif expiry_str.isdigit():
    expiry = datetime.datetime.strptime(expiry_str, '%Y%m%d')
    contract_type = find_contract_type_from_expiry(current_datetime, expiry)
  else:
    raise ValueError(expiry_str)
  return expiry, contract_type


def parse_native_expiry_contract_type(expiry_str, current_datetime):
  if expiry_str == 'PERPETUAL':
    expiry = PERPETUAL_DATE
    contract_type = 'perpetual'
  else:
    assert len(expiry_str) == 7
    # Uppercase month code need to be change to titlecase.
    d, m, y = expiry_str[:2], expiry_str[2:5], expiry_str[5:]
    m = m.title()
    expiry_str = d + m + y
    expiry = datetime.datetime.strptime(expiry_str, '%d%b%y')
    contract_type = find_contract_type_from_expiry(current_datetime, expiry)
  return expiry, contract_type


def to_native_expiry_str(expiry, contract_type):
  if contract_type == 'perpetual':
    assert expiry == PERPETUAL_DATE
    return 'PERPETUAL'
  elif contract_type in contract_type_list:
    # Titlecase month code need to be change to upper case.
    return expiry.strftime('%d%b%y').upper()
  else:
    raise ValueError(contract_type)


def find_quarter_contract_expiring_date(current_datetime):
  for idx, expiring_date_str in enumerate(quarter_contract_date):
    first_expiring_date = datetime.datetime.strptime(expiring_date_str, '%Y%m%d')
    first_expiring_date = exp_util.expiry_accurate_datetime(first_expiring_date)
    second_expiring_date = datetime.datetime.strptime(quarter_contract_date[idx + 1], '%Y%m%d')
    second_expiring_date = exp_util.expiry_accurate_datetime(second_expiring_date)

    if current_datetime < first_expiring_date:
      assert first_expiring_date - current_datetime < datetime.timedelta(days=88)
      return first_expiring_date
    elif first_expiring_date <= current_datetime < second_expiring_date:
      return second_expiring_date
    else:
      continue


def find_next_quarter_contract_expiring_date(current_datetime):
  for idx, expiring_date_str in enumerate(quarter_contract_date):
    first_expiring_date = datetime.datetime.strptime(expiring_date_str, '%Y%m%d')
    first_expiring_date = exp_util.expiry_accurate_datetime(first_expiring_date)
    second_expiring_date = datetime.datetime.strptime(quarter_contract_date[idx + 1], '%Y%m%d')
    second_expiring_date = exp_util.expiry_accurate_datetime(second_expiring_date)

    if current_datetime < first_expiring_date:
      assert first_expiring_date - current_datetime < datetime.timedelta(days=88)
      return second_expiring_date
    elif first_expiring_date <= current_datetime < second_expiring_date:
      third_expiring_date = datetime.datetime.strptime(quarter_contract_date[idx + 2], '%Y%m%d')
      third_expiring_date = exp_util.expiry_accurate_datetime(third_expiring_date)
      return third_expiring_date
    else:
      continue
